/*
 * PUBLIC DOMAIN PCCTS-BASED C++ GRAMMAR (cplusplus.g, stat.g, expr.g)
 *
 * Authors: Sumana Srinivasan, NeXT Inc.;            sumana_srinivasan@next.com
 *          Terence Parr, Parr Research Corporation; parrt@parr-research.com
 *          Russell Quong, Purdue University;        quong@ecn.purdue.edu
 *
 * VERSION 1.2
 *
 * SOFTWARE RIGHTS
 *
 * This file is a part of the ANTLR-based C++ grammar and is free
 * software.  We do not reserve any LEGAL rights to its use or
 * distribution, but you may NOT claim ownership or authorship of this
 * grammar or support code.  An individual or company may otherwise do
 * whatever they wish with the grammar distributed herewith including the
 * incorporation of the grammar or the output generated by ANTLR into
 * commerical software.  You may redistribute in source or binary form
 * without payment of royalties to us as long as this header remains
 * in all source distributions.
 *
 * We encourage users to develop parsers/tools using this grammar.
 * In return, we ask that credit is given to us for developing this
 * grammar.  By "credit", we mean that if you incorporate our grammar or
 * the generated code into one of your programs (commercial product,
 * research project, or otherwise) that you acknowledge this fact in the
 * documentation, research report, etc....  In addition, you should say nice
 * things about us at every opportunity.
 *
 * As long as these guidelines are kept, we expect to continue enhancing
 * this grammar.  Feel free to send us enhancements, fixes, bug reports,
 * suggestions, or general words of encouragement at parrt@parr-research.com.
 *
 * NeXT Computer Inc.
 * 900 Chesapeake Dr.
 * Redwood City, CA 94555
 * 12/02/1994
 *
 * Restructured for public consumption by Terence Parr late February, 1995.
 *
 * DISCLAIMER: we make no guarantees that this grammar works, makes sense,
 *             or can be used to do anything useful.
 */
/* 2001-2002
 * Version 1.0
 * This C++ grammar file has been converted from PCCTS to run under
 *  ANTLR to generate lexer and parser in C++ code by
 *  Jianguo Zuo and David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 *
 */
/* 2003
 * Version 2.0 was published by David Wigg in September 2003
 */
/* 2004
 * Version 3.0 July 2004
 * This is version 3.0 of the C++ grammar definition for ANTLR to
 *  generate lexer and parser in C++ code updated by
 *  David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 *
 * wiggjd@bcs.ac.uk
 * blackse@lsbu.ac.uk
 *
 * See MyReadMe.txt for further information
 *
 * This file is best viewed in courier font with tabs set to 4 spaces
 */
/* 2005
 * Version 0.01 February 2005
 * This is version 0.01 of the C++ grammar definition for ANTLR to
 * generate lexer and parser in Java code. This grammar was based
 * in the above version of the grammar by David Wigg, having been
 * ported to work in java programs.
 * The grammar file name is now different to enable diferentiation
 * from the original C++ grammar for C++ output. Many of the original
 * C++ grammar support files were removed, being for now the only
 * needed file the CPPvariables.java.
 *
 * This grammar is being developed in the context of the ArgoUML
 * project, being the basis for the C++ reverse engineering
 * functionalities of the C++ module.
 *
 * TODO: provide more documentation.
 * TODO: send to the ANTLR users list to enable review.
 * TODO: improve stand-alone use.
 *
 * www.argouml.org
 */

header
{
/*REMOVE_BEGIN*/
package com.google.test.metric.cpp;
/*REMOVE_END*/

import java.util.Hashtable;
import java.util.List;
import java.util.ArrayList;
}

class InternalParser extends Parser;

options
  {
  k = 2;
  exportVocab = STDC;
  codeGenMakeSwitchThreshold = 2;
  codeGenBitsetTestThreshold = 3;
  defaultErrorHandler=false;
  //analyzerDebug = true;
  }

{

  private Builder b;

  String enclosingClass="";//name of current class
  boolean _td=false; // is type declaration?
  Hashtable symbols=new Hashtable();


  public boolean qualifiedItemIsOneOf(java.util.BitSet  qiFlags, int lookahead_offset) throws TokenStreamException
  {
    java.util.BitSet qi = qualifiedItemIs(lookahead_offset);
    java.util.BitSet aux=(java.util.BitSet) qi.clone();
    aux.and(qiFlags);
    return (!aux.isEmpty());
  }


  // This is an important function, but will be replaced with
  // an enhanced predicate in the future, once predicates
  // and/or predicate guards can contain loops.
  //
  // Scan past the ::T::B:: to see what lies beyond.
  // Return QI_TYPE if the qualified item can pose as type name.
  // Note that T::T is NOT a type; it is a constructor.  Also,
  // class T { ... T...} yields the enclosed T as a ctor.  This
  // is probably a type as I separate out the constructor defs/decls,
  // I want it consistent with T::T.
  //
  // In the below examples, I use A,B,T and example types, and
  // a,b as example ids.
  // In the below examples, any A or B may be a
  // qualified template, i.e.,  A<...>
  //
  // T::T outside of class T yields QI_CTOR.
  // T<...>::T outside of class T yields QI_CTOR.
  // T inside of class T {...} yields QI_CTOR.
  // T, ::T, A::T outside of class T yields QI_TYPE.
  // a, ::a,  A::B::a yields qiId
  // a::b yields QI_INVALID
  // ::operator, operator, A::B::operator yield qiOPerator
  // A::*, A::B::* yield QI_PTR_MEMBER
  // ::*, * yields QI_INVALID
  // ::~T, ~T, A::~T yield QI_DTOR
  // ~a, ~A::a, A::~T::, ~T:: yield QI_INVALID
  public java.util.BitSet qualifiedItemIs(int lookahead_offset) throws TokenStreamException
  {
    int value;
    int k = lookahead_offset + 1;
    int final_type_idx = 0;
    boolean scope_found = false;
    // Skip leading "::"
    if (LT(k).getType() == SCOPE)
    {
      k++;
      scope_found = true;
    }
    // Skip sequences of T:: or T<...>::
    //printf("support.cpp qualifiedItemIs while reached k %d type %d isType %d, isClass %d, guessing %d\n",
    //  k,LT(k)->getType(),isTypeName((LT(k)->getText()).data()),isClassName((LT(k)->getText()).data()),inputState->guessing);
    while ((LT(k).getType() == ID) && (isTypeName(LT(k).getText())))
    {// If this type is the same as the last type, then ctor
      if ((final_type_idx != 0) && (LT(final_type_idx).getText().equals(LT(k).getText())))
      {// Like T::T
      // As an extra check, do not allow T::T::
        if (LT(k+1).getType() == SCOPE)
        { //printf("support.cpp qualifiedItemIs QI_INVALID returned\n");
          return CPPvariables.QI_INVALID;
        }
        else
        {//printf("support.cpp qualifiedItemIs QI_CTOR returned\n");
          return CPPvariables.QI_CTOR;
        }
      }

      // Record this as the most recent type seen in the series
      final_type_idx = k;

      //printf("support.cpp qualifiedItemIs if step reached final_type_idx %d\n",final_type_idx);

      // Skip this token
      k++;

      // Skip over any template qualifiers <...>
      // I believe that "T<..." cannot be anything valid but a template
      if (LT(k).getType() == LESSTHAN)
      {
        value=skipTemplateQualifiers(k);
        if (value==k)
        {//printf("support.cpp qualifiedItemIs QI_INVALID(2) returned\n");
          return CPPvariables.QI_INVALID;
        }
        else
          k=value;
        //printf("support.cpp qualifiedItemIs template skipped, k %d\n",k);
        // k has been updated to token following <...>
      }
      if (LT(k).getType() == SCOPE)
      // Skip the "::" and keep going
      {
        k++;
        scope_found = true;
      }
      else
      {// Series terminated -- last ID in the sequence was a type
      // Return ctor if last type is in containing class
      // We already checked for T::T inside loop
        if ( enclosingClass.equals(LT(final_type_idx).getText()))
        { // Like class T  T()
          //printf("support.cpp qualifiedItemIs QI_CTOR(2) returned\n");
          return CPPvariables.QI_CTOR;
        }
        else
        {//printf("support.cpp qualifiedItemIs QI_TYPE returned\n");
          return CPPvariables.QI_TYPE;
        }
      }
    }
    // LT(k) is not an ID, or it is an ID but not a typename.
    //printf("support.cpp qualifiedItemIs second switch reached\n");
    switch (LT(k).getType())
    {
      case ID:
        // ID but not a typename
        // Do not allow id::
        if (LT(k+1).getType() == SCOPE)
        {
        //printf("support.cpp qualifiedItemIs QI_INVALID(3) returned\n");
          return CPPvariables.QI_INVALID;
        }
        if (enclosingClass.equals(LT(k).getText()))
        { // Like class T  T()
          //printf("support.cpp qualifiedItemIs QI_CTOR(3) returned\n");
          return CPPvariables.QI_CTOR;
        }
        else
        {
          if (scope_found)
            // DW 25/10/03 Assume type if at least one SCOPE present (test12.i)
            return CPPvariables.QI_TYPE;
                else
            //printf("support.cpp qualifiedItemIs QI_VAR returned\n");
            return CPPvariables.QI_VAR; // DW 19/03/04 was QI_ID Could be function?
        }
      case TILDE:
        // check for dtor
        if ((LT(k+1).getType() == ID) && (isTypeName(LT(k+1).getText())) &&(LT(k+2).getType() != SCOPE))
        { // Like ~B or A::B::~B
           // Also (incorrectly?) matches ::~A.
          //printf("support.cpp qualifiedItemIs QI_DTOR returned\n");
          return CPPvariables.QI_DTOR;
        }
        else
        { // ~a or ~A::a is QI_INVALID
          //printf("support.cpp qualifiedItemIs QI_INVALID(4) returned\n");
          return CPPvariables.QI_INVALID;
        }
      case STAR:
        // Like A::*
        // Do not allow * or ::*
        if (final_type_idx == 0)
        { // Haven't seen a type yet
          //printf("support.cpp qualifiedItemIs QI_INVALID(5) returned\n");
          return CPPvariables.QI_INVALID;
        }
        else
        { //printf("support.cpp qualifiedItemIs QI_PTR_MEMBER returned\n");
          return CPPvariables.QI_PTR_MEMBER;
        }
      case OPERATOR:
        // Like A::operator, ::operator, or operator
        //printf("support.cpp qualifiedItemIs QI_OPERATOR returned\n");
        return CPPvariables.QI_OPERATOR;
      default:
        // Something that neither starts with :: or ID, or
        // a :: not followed by ID, operator, ~, or *
        //printf("support.cpp qualifiedItemIs QI_INVALID(6) returned\n");
        return CPPvariables.QI_INVALID;
    }
  }

  // Skip over <...>.  This correctly handles nested <> and (), e.g:
  //    <T>
  //    < (i>3) >
  //    < T2<...> >
  // but not
  //    < i>3 >
  //
  // On input, kInOut is the index of the "<"
  // On output, if the return is true, then
  //                kInOut is the index of the token after ">"
  //            else
  //                kInOut is unchanged

  public int skipTemplateQualifiers(int kInOut)  throws TokenStreamException
  {
    // Start after "<"
    int k = kInOut + 1;
    int value;
    while (LT(k).getType() != GREATERTHAN) // scan to end of <...>
    {
      switch (LT(k).getType())
      {
        case EOF:
          return kInOut;
        case LESSTHAN:
            value=skipTemplateQualifiers(k);
          if (value==k)
          {
            return kInOut;
          }
          else
            k=value;
          break;
        case LPAREN:
          value=skipNestedParens(k);
          if (value==k)
          {
            return kInOut;
          }
          else
            k=value;
          break;
        default:
          k++;     // skip everything else
          break;
      }
      if (k > CPPvariables.MAX_TEMPLATE_TOKEN_SCAN)
      {
        return kInOut;
      }
    }

  // Update output argument to point past ">"
  kInOut = k + 1;
  return kInOut;
  }

  // Skip over (...).  This correctly handles nested (), e.g:
  //    (i>3, (i>5))
  //
  // On input, kInOut is the index of the "("
  // On output, if the return is true, then
  //                kInOut is the index of the token after ")"
  //            else
  //                kInOut is unchanged
  public int skipNestedParens(int kInOut)  throws TokenStreamException
  {
    // Start after "("
    int k = kInOut + 1;
    int value;
    while (LT(k).getType() != RPAREN)   // scan to end of (...)
    {
      switch (LT(k).getType())
      {
        case EOF:
          return kInOut;
        case LPAREN:
          value=skipNestedParens(k);
          if (value==k)
          {
            return kInOut;
          }
          else
            k=value;
          break;
        default:
          k++;     // skip everything else
          break;
      }
      if (k > CPPvariables.MAX_TEMPLATE_TOKEN_SCAN)
      {
        return kInOut;
      }
    }
    // Update output argument to point past ")"
    kInOut = k + 1;
    return kInOut;
  }

  // Return true if "::blah" or "fu::bar<args>::..." found.
  public boolean scopedItem(int k)  throws TokenStreamException
  {
    //printf("support.cpp scopedItem k %d\n",k);
    return (LT(k).getType()==SCOPE ||
      (LT(k).getType()==ID && !finalQualifier(k)));
  }

  // Return true if ID<...> or ID is last item in qualified item list.
  // Return false if LT(k) is not an ID.
  // ID must be a type to check for ID<...>,
  // or else we would get confused by "i<3"
  public boolean finalQualifier(int k)  throws TokenStreamException
  {
    if (LT(k).getType()==ID)
    {
      if ((isTypeName(LT(k).getText())) && (LT(k+1).getType()==LESSTHAN))
      {
        // Starts with "T<".  Skip <...>
        k++;
        k=skipTemplateQualifiers(k);
      }
      else
      {
        // skip ID;
        k++;
      }
      return (LT(k).getType() != SCOPE );
    }
    else
    { // not an ID
      return false;
    }
  }

  /*
   * Return true if 's' can pose as a type name
   */
  public boolean isTypeName(String s)
  {
    String type="";
    if (!symbols.containsKey(s))
    {
      //printf("support.cpp isTypeName %s not found\n",s);
      return false;
    }
    else
      type=(String) symbols.get(s);
    if (type.equals(CPPvariables.OT_TYPE_DEF)||
      type.equals(CPPvariables.OT_ENUM)||
      type.equals(CPPvariables.OT_CLASS)||
      type.equals(CPPvariables.OT_STRUCT)||
      type.equals(CPPvariables.OT_UNION))
    {
      return true;
    }
    return false;
  }

  public void declaratorID(String id, java.util.BitSet qi)
  {
    if ((qi.equals(CPPvariables.QI_TYPE)) || (_td)) // Check for type declaration
    {
      if (!symbols.containsKey(id))
        symbols.put(id, CPPvariables.OT_TYPE_DEF);
    }
  }
}


translation_unit [Builder builder]
  {
    if(!symbols.containsKey("std"))
      symbols.put("std",CPPvariables.OT_TYPE_DEF);
    b = builder;
  }
   :  {b.beginTranslationUnit();}
      (external_declaration)+ EOF
      {b.endTranslationUnit();}
   ;


external_declaration
  {String s="";}
  :
  (
  // Template explicit specialisation (DW 14/04/03)
    ("template" LESSTHAN GREATERTHAN)=>"template" LESSTHAN GREATERTHAN declaration
  |
  // Class definition (templates too)
  // This is separated out otherwise the next alternative
  // would look for "class A { ... } f() {...}" which is
  // an unacceptable level of backtracking.

  // JEL Note:  Rule body does not need typedef, because
  // that is internal to "declaration", and it is invalid
  // to say "typedef template..."
    // Class definition
    (("typedef")? class_head)=> declaration
  |
    // Class template definition
    (template_head class_head)=>template_head declaration
   |
    // Enum definition (don't want to backtrack over this in other alts)
    ("enum" (ID)? LCURLY)=>enum_specifier (init_declarator_list)? SEMICOLON
   |
    // Destructor DEFINITION (templated or non-templated)
    ((template_head)? dtor_head LCURLY)=>(template_head)? dtor_head dtor_body
  |
    // Constructor DEFINITION (non-templated)
    // JEL 4/3/96 Added predicate that works, once the
    // restriction is added that ctor cannot be virtual
    // and ctor_declarator uses a more restrictive id
    ( (options {warnWhenFollowAmbig = false;}:
       ctor_decl_spec)?
      {qualifiedItemIsOneOf(CPPvariables.QI_CTOR,0)}?)=>ctor_definition
      /*(ID SCOPE)=>ctor_definition*/
   |
    // User-defined type cast
    (("inline")? scope_override  conversion_function_decl_or_def)=>
    ("inline")? s = scope_override conversion_function_decl_or_def
   |
    // Function declaration
    (declaration_specifiers function_declarator SEMICOLON)=>
    {b.beginFunctionDeclaration();}
    declaration
    {b.endFunctionDeclaration();}
  |
    // Function definition
    (declaration_specifiers function_declarator LCURLY)=>
    {b.beginFunctionDefinition(LT(2).getLine());}
    function_definition
    {b.endFunctionDefinition();}
  |
    // K & R Function definition
    (declaration_specifiers function_declarator declaration)=>function_definition
  |
    // templated forward class decl, init/decl of static member in template
    (template_head declaration_specifiers (init_declarator_list)? SEMICOLON )=>
    template_head declaration_specifiers (init_declarator_list)? SEMICOLON
  |
    // Templated FUNCTIONS and CONSTRUCTORS matched here.
    template_head
    (
      // Templated CONSTRUCTOR definition
            // JEL 4/3/96 Added predicate that works once the
            // restriction is added that ctor cannot be virtual
      ( ctor_decl_spec {qualifiedItemIsOneOf(CPPvariables.QI_CTOR,0)}?)=>ctor_definition
    |
      // Templated function declaration
      (declaration_specifiers function_declarator SEMICOLON)=> declaration
    |
      // Templated function definition
      (declaration_specifiers function_declarator LCURLY)=> function_definition
    )
  |
    decl_namespace
  |
     // everything else (except templates)
    declaration
  |
    SEMICOLON
  )
  ; // end of external_declaration

decl_namespace
  {String qid="";}
  :
    "namespace"
    (
      (ns:ID{ _td = true;declaratorID(ns.getText(),CPPvariables.QI_TYPE);})?

      // The following statement can be invoked to trigger selective antlr trace
      // Also see below
      //{if (strcmp((ns->getText()).data(),"xyz")==0) antlrTrace(true);}  // Used for diagnostic trigger
      LCURLY
      {if(ns == null) { b.enterNamespaceScope(null); }
       else { b.enterNamespaceScope(ns.getText()); }}
      (external_declaration)*
      {b.exitNamespaceScope();}
      RCURLY
      // The following should be implemented to match the optional statement above
      //{antlrTrace(false);}
    |
      ns2:ID {_td=true;declaratorID(ns2.getText(),CPPvariables.QI_TYPE);}
      ASSIGNEQUAL qid = qualified_id SEMICOLON
      {b.makeNamespaceAlias(qid, ns2.getText());}
    )
  ;

member_declaration
  {String q="";}
  :
  {b.beginMemberDeclaration();}
  (
    // Class definition
    // This is separated out otherwise the next alternative
    // would look for "class A { ... } f() {...}" which is
    // an unacceptable level of backtracking.
    ( ("typedef")? class_head) => declaration
  |
    // Enum definition (don't want to backtrack over this in other alts)
    ("enum" (ID)? LCURLY)=>enum_specifier (member_declarator_list)? SEMICOLON
  |
    (template_head class_head)=>template_head declaration
  |
    // Constructor declarator
    ( ctor_decl_spec {qualifiedItemIsOneOf(CPPvariables.QI_CTOR,0)}? ctor_declarator SEMICOLON)=>
    ctor_decl_spec ctor_declarator SEMICOLON  // Constructor declarator
  |
    // JEL Predicate to distinguish ctor from function
    // This works now that ctor cannot have VIRTUAL
    // It unfortunately matches A::A where A is not enclosing
    // class -- this will have to be checked semantically
    ( ctor_decl_spec
        {qualifiedItemIsOneOf(CPPvariables.QI_CTOR,0)}?
      ctor_declarator
      (COLON        // DEFINITION :ctor_initializer
      |LCURLY       // DEFINITION (compound Statement) ?
      )
    )=>ctor_definition
   |
    // No template_head allowed for dtor member
    // Backtrack if not a dtor (no TILDE)
    (dtor_head SEMICOLON)=>dtor_head SEMICOLON  // Declaration
  |
    // No template_head allowed for dtor member
    // Backtrack if not a dtor (no TILDE)
    (dtor_head LCURLY)=>dtor_head dtor_body // Definition
  |
    // Function declaration
    (declaration_specifiers function_declarator SEMICOLON)=>
    {b.beginFunctionDeclaration();}
    declaration
    {b.endFunctionDeclaration();}
  |
    // Function definition
    (declaration_specifiers function_declarator LCURLY)=>
    {b.beginFunctionDefinition(LT(2).getLine());}
    function_definition
    {b.endFunctionDefinition();}
  |
    // User-defined type cast
    (("inline")? conversion_function_decl_or_def)=>("inline")? conversion_function_decl_or_def
  |
    // Hack to handle decls like "superclass::member",
    // to redefine access to private base class public members
    (qualified_id SEMICOLON)=>q = qualified_id SEMICOLON
  |
    // Member with a type or just a type def
    // A::T a(), ::T a, ::B a, void a, E a (where E is the enclosing class)
    (declaration_specifiers)=>declaration_specifiers (member_declarator_list)? SEMICOLON

  |
     // Member without a type (I guess it can only be a function declaration or definition)
      (function_declarator SEMICOLON)=> function_declarator SEMICOLON

  |   // Member without a type (I guess it can only be a function definition)
        function_declarator compound_statement

   |
    // templated forward class decl, init/decl of static member in template
    // DW 27/06/03 Copied here from external_declaration since templates can now be nested
    (template_head declaration_specifiers (init_declarator_list)? SEMICOLON)=>
     template_head declaration_specifiers (init_declarator_list)? SEMICOLON
  |
    // Templated FUNCTIONS and CONSTRUCTORS matched here.
    // DW 27/06/03 Copied here from external_declaration since templates can now be nested
    template_head
    (
      // Templated CONSTRUCTOR definition
      // JEL 4/3/96 Added predicate that works once the
      // restriction is added that ctor cannot be virtual
      (ctor_decl_spec {qualifiedItemIsOneOf(CPPvariables.QI_CTOR,0)}?)=>ctor_definition
    |
      // Templated function declaration
      (declaration_specifiers function_declarator SEMICOLON)=>declaration
    |
      // Templated function definition
      // Function definition DW 2/6/97
      (declaration_specifiers function_declarator LCURLY)=> function_definition
    |
      conversion_function_decl_or_def
    )
  |
    access_specifier COLON
  |
    SEMICOLON
  )
  {b.endMemberDeclaration();}
  ; // end member_declaration


function_definition
{java.util.BitSet auxBitSet=(java.util.BitSet)CPPvariables.QI_TYPE.clone(); auxBitSet.or(CPPvariables.QI_CTOR);}
  : // don't want next action as an init-action due to (...)=> caller
  ( // Next line is equivalent to guarded predicate in PCCTS
    // (SCOPE | ID)? => <<qualifiedItemisOneOf(QI_TYPE|QI_CTOR)>>?
    {( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(auxBitSet,0) )}?
    declaration_specifiers function_declarator
    ( options{warnWhenFollowAmbig = false;}:
      (declaration)*  // Possible for K & R definition
    )?  compound_statement
  | // Next line is equivalent to guarded predicate in PCCTS
    // (SCOPE | ID)? => <<qualifiedItemisOneOf(QI_PTR_MEMBER)>>?
    //{( !(LA(1)==SCOPE||LA(1)==ID) || (qualifiedItemIsOneOf(QI_PTR_MEMBER)) )}?
    function_declarator
    ( options{warnWhenFollowAmbig = false;}:
      (declaration)*  // Possible for K & R definition
    )? compound_statement
  )
  ;

declaration
  :
    ("extern" StringLiteral)=> linkage_specification
  |
    // LL 31/1/97: added (COMMA) ? below. This allows variables to typedef'ed more than once. DW 18/08/03 ?
    declaration_specifiers ((COMMA)? init_declarator_list)? SEMICOLON
  |
    using_declaration // DW 19/04/04
  ;

linkage_specification
  : "extern"
    StringLiteral
    (LCURLY (external_declaration)* RCURLY
    |declaration
    )
  ;

declaration_specifiers
  {_td=false; boolean td=false; List declSpecs = new ArrayList();}
  :
  ( (options {warnWhenFollowAmbig = false;}
    : storage_class_specifier
    | type_qualifier
    | ("inline"|"_inline"|"__inline") {declSpecs.add("inline");}
    | "virtual"             {declSpecs.add("virtual");}
    | "explicit"            {declSpecs.add("explicit");}
    | "typedef"           {td=true; declSpecs.add("typedef");}
    | "friend"            {declSpecs.add("friend");}
    | ("_stdcall"|"__stdcall")    {declSpecs.add("__stdcall");}
    |   ("_declspec"|"__declspec") LPAREN ID RPAREN // euluis: ignore
    )* {if (!declSpecs.isEmpty()) b.declarationSpecifiers(declSpecs);}
    type_specifier
  |
    "typename"  {td=true;} direct_declarator
  )
  {_td=td;}
  ;

storage_class_specifier
  : "auto"    {b.storageClassSpecifier("auto");}
   |  "register"  {b.storageClassSpecifier("register");}
  | "static"  {b.storageClassSpecifier("static");}
  | "extern"  {b.storageClassSpecifier("extern");}
  | "mutable"   {b.storageClassSpecifier("mutable");}
  ;

type_qualifier // aka cv_qualifier
  :  ("const"|"const_cast")   {b.typeQualifier("const");} // euluis TODO: const_cast ?!?
  |  "volatile"       {b.typeQualifier("volatile");}
  ;

type_specifier
  :  simple_type_specifier
  | class_specifier
  | enum_specifier
  ;

simple_type_specifier
  { String s="";
    java.util.BitSet auxBitSet=(java.util.BitSet)CPPvariables.QI_TYPE.clone();
    auxBitSet.or(CPPvariables.QI_CTOR);
    List sts = new ArrayList();
  }
  : ( {qualifiedItemIsOneOf(auxBitSet,0)}?
       s = qualified_type
      {sts.add(s); b.simpleTypeSpecifier(sts);}
    |
      ( "char"          {sts.add("char");}
      | "wchar_t"       {sts.add("wchar_t");}
      | "bool"          {sts.add("bool");}
      | "short"         {sts.add("short");}
      | "int"         {sts.add("int");}
      | ("_int64"|"__int64")  {sts.add("__int64");}
      | "__w64"         {sts.add("__w64");}
      | "long"          {sts.add("long");}
      | "signed"        {sts.add("signed");}
      | "unsigned"        {sts.add("unsigned");}
      | "float"         {sts.add("float");}
      | "double"        {sts.add("double");}
      | "void"            {sts.add("void");}
      | ("_declspec"|"__declspec") LPAREN ID RPAREN //euluis: ignore
      )+ {b.simpleTypeSpecifier(sts);}
    )

  ;

qualified_type returns [String q=""]
  {String s=""; String  qitem="";}
  :
    // JEL 3/29/96 removed this predicate and moved it upwards to
    // simple_type_specifier.  This was done to allow parsing of ~ID to
    // be a unary_expression, which was never reached with this
    // predicate on
    //{qualifiedItemIsOneOf(QI_TYPE|QI_CTOR,0)}?

    s = scope_override
    id:ID
    (options {warnWhenFollowAmbig = false;}:
     LESSTHAN template_argument_list GREATERTHAN)?
    {
      qitem=s;
      qitem=qitem+id.getText();
      q=qitem;
    }
  ;

class_specifier
    {String saveClass="";String id="";String type="";}
  : ("class" {type=CPPvariables.OT_CLASS;}
    |"struct" {type=CPPvariables.OT_STRUCT;}
    |"union"  {type=CPPvariables.OT_UNION;}
    )
    ( id = qualified_id
      (options{generateAmbigWarnings = false;}:
        { saveClass = enclosingClass;
          enclosingClass = id;
        }
        {b.beginClassDefinition(type, id);}
        (base_clause)?
        LCURLY
        {
          if(!symbols.containsKey(id))
            symbols.put(id,type);
        }
        (member_declaration )*
        {b.endClassDefinition();}
        RCURLY
        { enclosingClass = saveClass;}
      |
        {

          String auxName=id;
            int pos = auxName.indexOf("::");
            while(pos>=0)
            {
            if(!symbols.containsKey(auxName.substring(0,pos)))
              symbols.put(auxName.substring(0,pos),type);
            auxName=auxName.substring(pos+2,auxName.length());
            pos=auxName.indexOf("::");
          }
          if(!symbols.containsKey(auxName))
              symbols.put(auxName,type);
        }
      )
    |
      LCURLY
      { id="anonymous";
          saveClass = enclosingClass; enclosingClass = "anonymous";
        if(!symbols.containsKey(id))
          symbols.put(id,type);
      }
      (member_declaration)* RCURLY
      {enclosingClass = saveClass;}
    )
  ;

enum_specifier
  : "enum"
    ( LCURLY
        enumerator_list RCURLY
    | id:ID     // DW 22/04/03 Suggest qualified_id here to satisfy elaborated_type_specifier
      { if(!symbols.containsKey(id.getText()))
          symbols.put(id.getText(),CPPvariables.OT_ENUM);
      }
      (  LCURLY enumerator_list RCURLY)?
    )
  ;

enumerator_list
  : enumerator (COMMA enumerator)*

  ;

enumerator
  : id:ID (ASSIGNEQUAL constant_expression)?

  ;

/* This matches a generic qualified identifier ::T::B::foo
 * (including OPERATOR).
 * It might be a good idea to put T::~dtor in here
 * as well, but id_expression in expr.g puts it in manually.
 * Maybe not, 'cause many people use this assuming only A::B.
 * How about a 'qualified_complex_id'?
 */
qualified_id returns [String q=""]
  {
  String so="";
  String qitem="";
  }
  :
  so =  scope_override
  {qitem=so; }
  (
  id:ID
   (options{warnWhenFollowAmbig = false;}:
  LESSTHAN template_argument_list GREATERTHAN)?
  {
    qitem=qitem+id.getText();
  }
  |
  OPERATOR optor
  {qitem=qitem+"operator"+"NYI";}
  |
  "this"  // DW 21/07/03 fix to pass test8.i
  |
  ("true"|"false")  // DW 21/07/03 fix to pass test8.i
  )
  {q = qitem;}
  ;

typeID
  : {isTypeName(LT(1).getText())}?
    ID
  ;

init_declarator_list
  : {b.beginInitDeclaratorList();}
    init_declarator (COMMA init_declarator)*
    {b.endInitDeclaratorList();}
  ;

init_declarator
  : declarator
    (
      ASSIGNEQUAL
        // check for initialisation and assignment (e.g. int x = 10;)
      initializer
    |
      LPAREN expression_list RPAREN
    )?
  ;

initializer
  :
  {b.beginInitializer();}
  (
      remainder_expression // DW 18/4/01 assignment_expression
    |
      LCURLY initializer (COMMA initializer)* RCURLY
  )
  {b.endInitializer();}
  ;

class_head
  : // Used only by predicates
  ("struct"
  |"union"
  |"class"
  )
    (ID
    (LESSTHAN template_argument_list GREATERTHAN)?
    (base_clause)?
  )? LCURLY
  ;

base_clause
  :
     COLON base_specifier (COMMA base_specifier)*
  ;

base_specifier
  {String qt=""; b.beginBaseSpecifier();}
  : // DW 13/08/03 Should check qualified_type for class-name?
    ( "virtual" ( access_specifier)? qt = qualified_type {b.baseSpecifier(qt, true);}
      |  access_specifier "virtual" qt = qualified_type {b.baseSpecifier(qt, true);}
      |  access_specifier qt = qualified_type {b.baseSpecifier(qt, false);}
      | qt = qualified_type {b.baseSpecifier(qt, false);}
    )
    {b.endBaseSpecifier();}
  ;

access_specifier
  : "public" {b.accessSpecifier("public");}
  | "protected" {b.accessSpecifier("protected");}
  | "private"  {b.accessSpecifier("private");}
  ;

member_declarator_list
  : member_declarator (ASSIGNEQUAL OCTALINT)? // The value must be 0 (pure virt.)
    (COMMA member_declarator (ASSIGNEQUAL OCTALINT)? )*
  ;

member_declarator
  :
    ((ID)? COLON constant_expression)=>(ID)? COLON constant_expression
  |
    declarator
  ;

conversion_function_decl_or_def
  : OPERATOR
      declaration_specifiers
    (STAR | AMPERSAND)? // DW 01/08/03 Use type_specifier here? see syntax
    (LESSTHAN template_parameter_list GREATERTHAN)?
    LPAREN (parameter_list)? RPAREN
    (type_qualifier)?
    (exception_specification)?
    ( compound_statement
    | SEMICOLON
    )
  ;

// JEL note:  does not use (const|volatile)* to avoid lookahead problems
cv_qualifier_seq
  :
  (type_qualifier)*
  ;

declarator
  :
    //{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(QI_PTR_MEMBER) )}?
    (ptr_operator)=>ptr_operator  // AMPERSAND or STAR
    declarator
  |
    direct_declarator
  ;

direct_declarator
  {String id="";}
  :
    (qualified_id LPAREN (RPAREN|declaration_specifiers) )=>  // Must be function declaration
    id = qualified_id {declaratorID(id,CPPvariables.QI_FUN); b.directDeclarator(id);}
    LPAREN (parameter_list)? RPAREN (type_qualifier)* (exception_specification)?
  | (qualified_id LPAREN qualified_id)=>  // Must be class instantiation
    id = qualified_id {declaratorID(id,CPPvariables.QI_VAR);}LPAREN expression_list RPAREN
  |
    (qualified_id LSQUARE)=>  // Must be array declaration
    id = qualified_id
    {
       if (_td==true)
        declaratorID(id,CPPvariables.QI_TYPE);
       else
        declaratorID(id,CPPvariables.QI_VAR);
    }
    (options {warnWhenFollowAmbig = false;}:
     LSQUARE (constant_expression)? RSQUARE)+
  |
    id = qualified_id
    {
      if (_td==true)
        declaratorID(id,CPPvariables.QI_TYPE);
      else {
        declaratorID(id,CPPvariables.QI_VAR);
        b.directDeclarator(id);
      }
    }
  |
    // DW 24/05/04 This block probably never entered as dtor selected out earlier
    //  Note In fact no dictionary entries for ctor or dtor
    TILDE dtor:ID   {declaratorID(dtor.getText(),CPPvariables.QI_DTOR);}// Note "class" not recorded in CPPSymbol
    LPAREN (parameter_list)? RPAREN

  |

    LPAREN declarator RPAREN declarator_suffixes
  ;



declarator_suffixes
  {java.util.BitSet auxBitSet=(java.util.BitSet)CPPvariables.QI_TYPE.clone(); auxBitSet.or(CPPvariables.QI_CTOR);}
  :
  (
    (options {warnWhenFollowAmbig = false;}:
     LSQUARE (constant_expression)? RSQUARE)+
  | {(!((LA(1)==LPAREN)&&(LA(2)==ID))||(qualifiedItemIsOneOf(auxBitSet,1)))}?
    LPAREN (parameter_list)? RPAREN (type_qualifier)* (exception_specification)?
//  | // DW 28/06/04 deleted Assume either following bracketed declaration
//    // empty
  )
  ;

/* I think something is weird with the context-guards for predicates;
 * as a result I manually hoist the appropriate pred from ptr_to_member
 *
 * TER: warning: seems that "ID::" will always bypass and go to 2nd alt :(
 */
function_declarator
  :
    //{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(QI_PTR_MEMBER) )}?
    (ptr_operator)=> ptr_operator function_declarator
  |
    function_direct_declarator
  ;

function_direct_declarator
  { String q="";}
  :
    /* predicate indicate that plain ID is ok here; this counteracts any
     * other predicate that gets hoisted (along with this one) that
     * indicates that an ID is a type or whatever.  E.g.,
     * another rule testing isTypeName() alone, implies that the
     * the ID *MUST* be a type name.  Combining isTypeName() and
     * this predicate in an OR situation like this one:
     * ( declaration_specifiers ... | function_declarator ... )
     * would imply that ID can be a type name OR a plain ID.
     */
    ( // fix prompted by (isdigit)() in xlocnum
      LPAREN
      q = qualified_id
      {
        declaratorID(q,CPPvariables.QI_FUN);
      }
      RPAREN
    |
      q = qualified_id
      {
        declaratorID(q,CPPvariables.QI_FUN);
      }
    )
    {b.functionDirectDeclarator(q);}

    LPAREN (parameter_list)? RPAREN
    (options{warnWhenFollowAmbig = false;}:
     type_qualifier)*
    (ASSIGNEQUAL OCTALINT)? // The value of the octal must be 0
    (exception_specification)?
  ;

ctor_definition
  :
  {b.beginCtorDefinition();}
  ctor_head
  ctor_body
  {b.endCtorDefinition();}
  ;

ctor_head
  :
  ctor_decl_spec ctor_declarator
  ;

ctor_decl_spec
  {List declSpecs = new ArrayList();}
  :
  ( ("inline"|"_inline"|"__inline") {declSpecs.add("inline");}
    |
    "explicit" {declSpecs.add("explicit");}
  )*
  {b.declarationSpecifiers(declSpecs);}
  ;

ctor_declarator
  { String q="";}
  :
    // JEL 4/3/96 qualified_id too broad DW 10/06/03 ?
    q = qualified_ctor_id  {b.qualifiedCtorId(q);}
    LPAREN (parameter_list)? RPAREN (exception_specification)?
  ;

// This matches a generic qualified identifier ::T::B::foo
// that is satisfactory for a ctor (no operator, no trailing <>)
qualified_ctor_id returns [String q=""]
  {
  String so="";
  String qitem="";
  }
  :
  so = scope_override
  {qitem=so;}
  id:ID // DW 24/05/04 Note. Neither Ctor or Dtor recorded in dictionary
  {qitem=qitem+id.getText();
   q = qitem;}
  ;

ctor_body
  :
  (ctor_initializer)? compound_statement
  ;

ctor_initializer
  :
  COLON superclass_init (COMMA superclass_init)*
  ;

superclass_init
  {String q="";}
  :
  q = qualified_id LPAREN (expression_list)? RPAREN
  ;

dtor_head
  :
  {b.beginDtorHead();}
  dtor_decl_spec dtor_declarator
  {b.endDtorHead();}
  ;

dtor_decl_spec
  {List declSpecs = new ArrayList();}
  :
  (
    ("inline"|"_inline"|"__inline") {declSpecs.add("inline");}
    |
    "virtual" {declSpecs.add("virtual");}
  )*
  {b.declarationSpecifiers(declSpecs);}
  ;

dtor_declarator
  {String s="";}
  :
  s = scope_override

  TILDE id:ID
  {b.dtorDeclarator(s+"~"+id.getText());}
  LPAREN RPAREN (exception_specification)?
  ;

dtor_body
  :
  compound_statement
  ;

parameter_list
  : parameter_declaration_list (ELLIPSIS)?
  ;

parameter_declaration_list
  :
  ( parameter_declaration
    (// Have not been able to find way of stopping warning of non-determinism between alt 1 and exit branch of block
     COMMA parameter_declaration
    )*
  )
  ;

parameter_declaration
  {java.util.BitSet auxBitSet=(java.util.BitSet)CPPvariables.QI_TYPE.clone(); auxBitSet.or(CPPvariables.QI_CTOR);}
  : {b.beginParameterDeclaration();}
    (
      {!((LA(1)==SCOPE) && (LA(2)==STAR||LA(2)==OPERATOR))&&( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(auxBitSet,0) )}?
      declaration_specifiers  // DW 24/3/98 Mods for K & R
      (
        (declarator)=> declarator        // if arg name given
      |
        abstract_declarator     // if arg name not given  // can be empty
      )
    |
      (declarator)=> declarator     // DW 24/3/98 Mods for K & R
    |
      ELLIPSIS
    )
    (ASSIGNEQUAL
     remainder_expression // DW 18/4/01 assignment_expression
    )?
    {b.endParameterDeclaration();}
  ;

type_name // aka type_id
  :
  declaration_specifiers abstract_declarator
  ;

/* This rule looks a bit weird because (...) can happen in two
 * places within the declaration such as "void (*)()" (ptr to
 * function returning nothing).  However, the () of a function
 * can only occur after having seen either a (abstract_declarator)
 * and not after a [..] or simple '*'.  These are the only two
 * valid () func-groups:
 *    int (*)();     // ptr to func
 *    int (*[])();   // array of ptr to func
 */
abstract_declarator
  : //{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(QI_PTR_MEMBER) )}?
    ptr_operator abstract_declarator

  |
    LPAREN abstract_declarator RPAREN
    (abstract_declarator_suffix)+
  |
    (LSQUARE (constant_expression )? RSQUARE )+
  |
    /* empty */
  ;

abstract_declarator_suffix
  :
    LSQUARE (constant_expression)? RSQUARE
  |
    LPAREN (parameter_list)? RPAREN cv_qualifier_seq (exception_specification)?
  ;

exception_specification
  {String so="";}
  : "throw" LPAREN
    ( (so = scope_override ID (COMMA so = scope_override ID)* )?
    | ELLIPSIS
    )
    RPAREN
  ;

template_head
  :
    "template"
    LESSTHAN template_parameter_list GREATERTHAN
  ;

template_parameter_list
  :
    template_parameter (COMMA template_parameter)*
  ;

/* Rule requires >2 lookahead tokens. The ambiguity is resolved
 * correctly, however. According to the manual "...A template argument
 * that can be interpreted either as a parameter-declaration or a
 * type-argument (because its identifier is the name of an
 * already existing class) is taken as type-argument."
 * Therefore, any "class ID" that is seen on the input, should
 * match the first alternative here (it should be a type-argument).
 */
template_parameter
  :
  (options{generateAmbigWarnings = false;}:
    ("class"|"typename")
    (id:ID  (ASSIGNEQUAL assigned_type_name)? )?
    { if(!symbols.containsKey(id.getText()))
        symbols.put(id.getText(),CPPvariables.OT_TYPE_DEF);
    }
  |
    parameter_declaration // DW 30/06/03 This doesn't seem to match the current standard
  )
  ;

/* This is to allow an assigned type_name in a template parameter
 *  list to be defined previously in the same parameter list,
 *  as type setting is ineffective whilst guessing
 */
assigned_type_name
  {String s=""; }
  :
  (options{generateAmbigWarnings = false;}:
    s = qualified_type abstract_declarator
  |
    simple_type_specifier abstract_declarator
  )
  ;

// This rule refers to an instance of a template class or function
template_id // aka template_class_name
  : ID LESSTHAN template_argument_list GREATERTHAN
  ;

template_argument_list
  : template_argument (COMMA template_argument)*
  ;

/* Here assignment_expression was changed to shift_expression to rule out
 *  x< 1<2 > which causes ambiguities. As a result, these can be used only
 *  by enclosing parentheses x<(1<2)>. This is true for x<1+2> ==> bad,
 *  x<(1+2)> ==> ok.
 */
template_argument
{java.util.BitSet auxBitSet=(java.util.BitSet)CPPvariables.QI_TYPE.clone(); auxBitSet.or(CPPvariables.QI_CTOR);}
  :
    {( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(auxBitSet,0) )}?
    type_name
  |
    shift_expression // failed in iosfwd
//  | assignment_expression // Inserted as per grammar summary
  ;

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  STATEMENTS ////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

statement_list
  : (statement)+
  ;

statement
  :
  ( (declaration)=>declaration
  | labeled_statement
  | case_statement
  | default_statement
  |
    {b.beginExpressionStatement();}
    expression SEMICOLON
    {b.endExpressionStatement();}
  | compound_statement
  | selection_statement
  | iteration_statement
  | jump_statement
  | SEMICOLON
  | try_block
  | throw_statement
  | asm_block
  )
  ;

labeled_statement
  : ID COLON statement
  ;

case_statement
  : {b.beginCaseStatement();}
    "case"
    constant_expression COLON statement
    {b.endCaseStatement();}
  ;

default_statement
  : {b.beginDefaultStatement();}
    "default" COLON statement
    {b.endDefaultStatement();}
  ;

compound_statement
  :
    {b.beginCompoundStatement();}
    LCURLY (statement_list)? RCURLY
    {b.endCompoundStatement();}
  ;

/* NOTE: cannot remove ELSE ambiguity, but it parses correctly.
 * The warning is removed with the options statement
 */
selection_statement
  :
    {b.beginIfStatement();}
    "if" LPAREN expression RPAREN statement
    {b.endIfStatement();}
    (options {warnWhenFollowAmbig = false;}:
     {b.beginElseStatement();}
     "else" statement
     {b.endElseStatement();}
    )?
  |
    {b.beginSwitchStatement();}
    "switch" LPAREN  expression RPAREN statement
    {b.endSwitchStatement();}
  ;

iteration_statement
  :
    {b.beginWhileStatement();}
    "while" LPAREN expression RPAREN statement
    {b.endWhileStatement();}
  |
    {b.beginDoStatement();}
    "do" statement "while" LPAREN expression RPAREN SEMICOLON
    {b.endDoStatement();}
  |
    {b.beginForStatement();}
    "for" LPAREN
    ( (declaration)=> declaration
    | expression SEMICOLON
    | SEMICOLON
    )
    (expression)? SEMICOLON
    (expression)?
    RPAREN statement
    {b.endForStatement();}
  ;

jump_statement
  :
  ( "goto" ID SEMICOLON
    {b.gotoStatement();}
  | "continue" SEMICOLON
    {b.continueStatement();}
  | "break" SEMICOLON
    {b.breakStatement();}
    // DW 16/05/03 May be problem here if return is followed by a cast expression
  | {b.beginReturnStatement(LT(1).getLine());}
    "return"
    ( options{warnWhenFollowAmbig = false;}:
      (LPAREN {(qualifiedItemIsOneOf(CPPvariables.QI_TYPE,0) )}? ID RPAREN)=>
      LPAREN ID RPAREN (expression)?  // This is an unsatisfactory fix for problem in xstring re "return (allocator);"
                      //  and in xlocale re return (_E)(_Tolower((unsigned char)_C, &_Ctype));
      //{printf("%d CPP_parser.g jump_statement Return fix used\n",LT(1)->getLine());}
    | expression
    )?  SEMICOLON
    {b.endReturnStatement();}
  )
  ;

try_block
  : "try" compound_statement (handler)*
  ;


handler
  : "catch" LPAREN exception_declaration RPAREN compound_statement
  ;

exception_declaration
  : parameter_declaration_list
  ;

/* This is an expression of type void according to the ARM, which
 * to me means "statement"; it removes some ambiguity to put it in
 * as a statement also.
 */
throw_statement
  : "throw" (assignment_expression) ? SEMICOLON
  ;

using_declaration
  {String qid="";}
  : "using"
    ("namespace" qid = qualified_id // Using-directive
    |qid = qualified_id       // Using-declaration
    )
    SEMICOLON
  ;

asm_block
  : ("_asm"|"__asm") LCURLY (~RCURLY)* RCURLY
  ;

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  EXPRESSIONS ///////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

expression
  :
    {b.beginExpression();}
    assignment_expression (COMMA assignment_expression)*
    {b.endExpression();}
  ;

expression_list
  : assignment_expression (COMMA assignment_expression)*
  ;

/* right-to-left for assignment op */
assignment_expression
  :
    conditional_expression
    (
      {b.beginAssignmentExpression(LT(1).getLine());}
      (ASSIGNEQUAL
      |TIMESEQUAL|DIVIDEEQUAL|MINUSEQUAL|PLUSEQUAL
      |MODEQUAL
      |SHIFTLEFTEQUAL
      |SHIFTRIGHTEQUAL
      |BITWISEANDEQUAL
      |BITWISEXOREQUAL
      |BITWISEOREQUAL
      )
      remainder_expression
      {b.endAssignmentExpression();}
    )?
  ;

remainder_expression
  :
    ( (conditional_expression (COMMA|SEMICOLON|RPAREN)
      )=>
      assignment_expression
    |
      assignment_expression
    )
  ;

conditional_expression
  :
    logical_or_expression
    (
      {b.beginTernaryOperator();}
      QUESTIONMARK expression COLON conditional_expression
      {b.endTernaryOperator();}
    )?
  ;

constant_expression
  :
    conditional_expression
  ;

logical_or_expression
  :
    logical_and_expression (OR logical_and_expression)*
  ;

logical_and_expression
  :
    inclusive_or_expression (AND inclusive_or_expression)*
  ;

inclusive_or_expression
  :
    exclusive_or_expression (BITWISEOR exclusive_or_expression)*
  ;

exclusive_or_expression
  :
    and_expression (BITWISEXOR and_expression)*
  ;

and_expression
  :
  equality_expression (AMPERSAND  equality_expression)*
  ;

equality_expression
  :
    relational_expression ((NOTEQUAL | EQUAL) relational_expression)*
  ;

relational_expression
  : shift_expression
    (options {warnWhenFollowAmbig = false;}:
      ( LESSTHAN
      | GREATERTHAN
      | LESSTHANOREQUALTO
      | GREATERTHANOREQUALTO
      )
     shift_expression
    )*
  ;

shift_expression
  : additive_expression ((SHIFTLEFT | SHIFTRIGHT) additive_expression)*
  ;

/* See comment for multiplicative_expression regarding #pragma */
additive_expression
  : multiplicative_expression
    (options{warnWhenFollowAmbig = false;}:
      (PLUS | MINUS) multiplicative_expression
    )*
  ;

/* ANTLR has trouble dealing with the analysis of the confusing unary/binary
 * operators such as STAR, AMPERSAND, PLUS, etc...  With the #pragma (now "(options{warnWhenFollowAmbig = false;}:" etc.)
 * we simply tell ANTLR to use the "quick-to-analyze" approximate lookahead
 * as full LL(k) lookahead will not resolve the ambiguity anyway.  Might
 * as well not bother.  This has the side-benefit that ANTLR doesn't go
 * off to lunch here (take infinite time to read grammar).
 */
multiplicative_expression
  : pm_expression
    (options{warnWhenFollowAmbig = false;}:
      (STAR | DIVIDE | MOD) pm_expression
    )*
  ;

pm_expression
  : cast_expression ((DOTMBR | POINTERTOMBR) cast_expression)*
  ;

/* The string "( ID" can be either the start of a cast or
 * the start of a unary_expression.  However, the ID must
 * be a type name for it to be a cast.  Since ANTLR can only hoist
 * semantic predicates that are visible without consuming a token,
 * the semantic predicate in rule type_name is not hoisted--hence, the
 * rule is reported to be ambiguous.  I am manually putting in the
 * correctly hoisted predicate.
 *
 * Ack! Actually "( ID" might be the start of "(T(expr))" which makes
 * the first parens just an ordinary expression grouping.  The solution
 * is to look at what follows the type, T.  Note, this could be a
 * qualified type.  Yucko.  I believe that "(T(" can only imply
 * function-style type cast in an expression (...) grouping.
 *
 * We DO NOT handle the following situation correctly at the moment:
 * Suppose you have
 *    struct rusage rusage;
 *    return (rusage.fp);
 *    return (rusage*)p;
 * Now essentially there is an ambiguity here. If rusage is followed by any
 * postix operators then it is an identifier else it is a type name. This
 * problem does not occur in C because, unless the tag struct is attached,
 * rusage is not a type name. However in C++ that restriction is removed.
 * No *real* programmer would do this, but it's in the C++ standard just for
 * fun..
 *
 * Another fun one (from an LL standpoint):
 *
 *   (A::B::T *)v;      // that's a cast of v to type A::B::T
 *   (A::B::foo);    // that's a simple member access
 *
 * The qualifiedItemIs(1) function scans ahead to what follows the
 * final "::" and returns QI_TYPE if the item is a type.  The offset of
 * '1' makes it ignore the initial LPAREN; normally, the offset is 0.
 */

cast_expression
  :
    // DW 23/06/03
    (LPAREN (type_qualifier)? simple_type_specifier (ptr_operator)? RPAREN)=>
     LPAREN (type_qualifier)? simple_type_specifier (ptr_operator)? RPAREN cast_expression
  |
    unary_expression  // handles outer (...) of "(T(expr))"
  ;

unary_expression
  :
    ( //{!(LA(1)==TILDE && LA(2)==ID)||qualifiedItemIsOneOf(QI_VAR|QI_FUN|QI_DTOR|QI_CTOR)}?
      (postfix_expression)=> postfix_expression
    | PLUSPLUS unary_expression
    | MINUSMINUS unary_expression
    | unary_operator cast_expression
    | "sizeof"
      (// see comment for rule cast_expression for info on predicate
       // JEL NOTE 3/31/96 -- This won't work -- you really need to
       // call qualifiedItemIsOneOf(QI_TYPE|QI_CTOR,1)
       // The context should also be ( LPAREN (SCOPE|ID) )
       // ( LPAREN ID ) => {isTypeName((LT(2)->getText()).data())}?
       {(!(((LA(1)==LPAREN&&(LA(2)==ID))))||(isTypeName(LT(2).getText())))}?
        LPAREN type_name RPAREN
      | unary_expression
      )
    |
      (SCOPE)?
      (new_expression
      |delete_expression
      )
    )
  ;

postfix_expression
  {String function_name="";}
  :
  (
    options {warnWhenFollowAmbig = false;}:
    // Function-style cast must have a leading type
    {!(LA(1)==LPAREN)}?
    (simple_type_specifier LPAREN RPAREN LPAREN)=>  // DW 01/08/03 To cope with problem in xtree (see test10.i)
     simple_type_specifier LPAREN RPAREN LPAREN (expression_list)? RPAREN
  |
    {!(LA(1)==LPAREN)}?
    (simple_type_specifier LPAREN)=>
     simple_type_specifier LPAREN (expression_list)? RPAREN
  |
    {b.beginPostfixExpression();}
    primary_expression
    (options {warnWhenFollowAmbig = false;}:
      LSQUARE expression RSQUARE
    | LPAREN
        {b.beginParameterList();}
        (expression_list)?
        {b.endParameterList();}
      RPAREN
    | DOT
        {b.beginMemberAccess();}
        id_expression
        {b.endMemberAccess();}
    | POINTERTO
        {b.beginMemberAccess();}
        id_expression
        {b.endMemberAccess();}
    | PLUSPLUS
    | MINUSMINUS
    )*
    {b.endPostfixExpression();}
  |
    ("dynamic_cast"|"static_cast"|"reinterpret_cast"|"const_cast")  // Note const_cast in elsewhere
    LESSTHAN type_specifier (ptr_operator)? GREATERTHAN
    LPAREN expression RPAREN
  )
  ;

primary_expression
  :
  {b.beginPrimaryExpression();}
  id_expression
  | constant
  | "this"
  | LPAREN expression RPAREN
  {b.endPrimaryExpression();}
  ;

id_expression
  {String s="";}
  :
    s = scope_override
    (
      t:ID
      {b.idExpression(t.getText());}
    | OPERATOR optor
    | TILDE (STAR)? ID  // DW 29/07/03 STAR included to allow for *_S = ~*_S; seen in vector
    )
  ;

unary_operator
  : AMPERSAND
  | STAR
  | PLUS
  | MINUS
  | TILDE
  | NOT
  ;

/* JEL The first ()? is used to resolve "new (expr) (type)" because both
 * (expr) and (type) look identical until you've seen the whole thing.
 *
 * new_initializer appears to be conflicting with function arguments as
 * function arguments can follow a primary_expression.  [This is a full
 * LL(k) versus LALL(k) problem.  Enhancing context by duplication of
 * some rules might handle this.]
 */
new_expression
  :
  (
    "new"
    ((LPAREN expression_list RPAREN)=>
      LPAREN expression_list RPAREN)?
    (new_type_id | LPAREN type_name RPAREN)
    (options{warnWhenFollowAmbig = false;}:
    (new_initializer)=> new_initializer)?
  )
  ;

new_initializer
  : LPAREN (expression_list)? RPAREN
  ;

new_type_id
  : declaration_specifiers
    (options {warnWhenFollowAmbig = false;}:
     //{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(QI_PTR_MEMBER) )}?
      new_declarator
    )?
  ;

new_declarator
  : //{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(QI_PTR_MEMBER) )}?
    //ptr_to_member cv_qualifier_seq
    ptr_operator
    (options {warnWhenFollowAmbig = false;}:
    new_declarator ) ?
  | direct_new_declarator
  ;

ptr_operator
  :
    {b.beginPtrOperator();}
    ( AMPERSAND             {b.ptrOperator("&");}
    | ("_cdecl"|"__cdecl")
    | ("_near"|"__near")
    | ("_far"|"__far")
    | "__interrupt"
    | ("pascal"|"_pascal"|"__pascal")
    | ("_stdcall"|"__stdcall")
    | ptr_to_member // e.g. STAR; euluis (2005-07-13): calls
                    // b.ptrOperator("*") or b.ptrToMember(s, "*").
    )
    {b.endPtrOperator();}
   ;

// Match A::B::*
ptr_to_member
  {String s="";}
  :
  s = scope_override STAR
  {
    if (s.length() != 0) b.ptrToMember(s, "*");
    else b.ptrOperator("*");
  }
  cv_qualifier_seq
  ;

// Match the A::B::C:: or nothing
scope_override returns [String s=""]
  {
    String sitem="";
  }
  :
    //{!(qualifiedItemIsOneOf(QI_TYPE))}?
    (SCOPE {sitem=sitem+"::";})?
    ( options {warnWhenFollowAmbig = false;}:
      {scopedItem(1)}?
      id:ID (LESSTHAN template_argument_list GREATERTHAN)? SCOPE
      {
        sitem=sitem+id.getText();
        sitem=sitem+"::";
      }
    )*
  {s = sitem;}
  ;

/* The "[expression]" construct conflicts with the "new []" construct
 * (and possibly others).  We used approximate lookahead for the "new []"
 * construct so that it would not try to compute full LL(2) lookahead.
 * Here, we use #pragma approx again because anytime we see a [ followed
 * by token that can begin an expression, we always want to loop.
 * Approximate lookahead handles this correctly.  In fact, approximate
 * lookahead is the same as full lookahead when all but the last lookahead
 * depth are singleton sets; e.g., {"["} followed by FIRST(expression).
 */


direct_new_declarator
  :
    (options {warnWhenFollowAmbig = false;}:
      LSQUARE expression RSQUARE
    )+
  ;

delete_expression
  : "delete" (LSQUARE RSQUARE)? cast_expression
  ;

constant
  : OCTALINT
  | DECIMALINT
  | HEXADECIMALINT
  | CharLiteral
  | (StringLiteral)+
  | FLOATONE
  | FLOATTWO
  | "true"
  | "false"
  ;

optor
  :
    "new"
    (options {warnWhenFollowAmbig = false;}:
      LSQUARE RSQUARE | )   // check syntax
  |
    "delete"
    (options {warnWhenFollowAmbig = false;}:
      LSQUARE RSQUARE | )   // check syntax
  | LPAREN RPAREN
  | LSQUARE RSQUARE
  | optor_simple_tokclass //OPTOR_SIMPLE_TOKCLASS
  ;

//Zuo 5/11/2001
// This is the equivalent to "#tokclass OPTOR_SIMPLE_TOKCLASS" in cplusplus.g

optor_simple_tokclass
  :
    (PLUS
    |MINUS
    |STAR
    |DIVIDE
    |MOD
    |BITWISEXOR
    |AMPERSAND
    |BITWISEOR
    |TILDE
    |NOT
    |SHIFTLEFT
    |SHIFTRIGHT
    |ASSIGNEQUAL
    |TIMESEQUAL
    |DIVIDEEQUAL
    |MODEQUAL
    |PLUSEQUAL
    |MINUSEQUAL
    |SHIFTLEFTEQUAL
    |SHIFTRIGHTEQUAL
    |BITWISEANDEQUAL
    |BITWISEXOREQUAL
    |BITWISEOREQUAL
    |EQUAL
    |NOTEQUAL
    |LESSTHAN
    |GREATERTHAN
    |LESSTHANOREQUALTO
    |GREATERTHANOREQUALTO
    |OR
    |AND
    |PLUSPLUS
    |MINUSMINUS
    |COMMA
    |POINTERTO
    |POINTERTOMBR
  )
  ;



// Zuo 19/11/01 from next line, the Lexer is derived from stdCParser.g

class InternalLexer extends Lexer;

options
  {
  k = 3;
  exportVocab = STDC;
  testLiterals = true;
  }

// DW 4/11/02 put in to support manual hoisting
tokens
  {
  OPERATOR = "operator";
  }


/* Operators: */

ASSIGNEQUAL     : '=' ;
COLON           : ':' ;
COMMA           : ',' ;
QUESTIONMARK    : '?' ;
SEMICOLON       : ';' ;
POINTERTO       : "->" ;

/*
// DOT & ELLIPSIS are commented out since they are generated as part of
// the Number rule below due to some bizarre lexical ambiguity shme.
// DOT  :       '.' ;
// ELLIPSIS      : "..." ;
*/

LPAREN          : '(' ;
RPAREN          : ')' ;
LSQUARE         : '[' ;
RSQUARE         : ']' ;
LCURLY          : '{' ;
RCURLY          : '}' ;

EQUAL           : "==" ;
NOTEQUAL        : "!=" ;
LESSTHANOREQUALTO     : "<=" ;
LESSTHAN              : "<" ;
GREATERTHANOREQUALTO  : ">=" ;
GREATERTHAN           : ">" ;

DIVIDE          : '/' ;
DIVIDEEQUAL     : "/=" ;
PLUS            : '+' ;
PLUSEQUAL       : "+=" ;
PLUSPLUS        : "++" ;
MINUS           : '-' ;
MINUSEQUAL      : "-=" ;
MINUSMINUS      : "--" ;
STAR            : '*' ;
TIMESEQUAL      : "*=" ;
MOD             : '%' ;
MODEQUAL        : "%=" ;
SHIFTRIGHT      : ">>" ;
SHIFTRIGHTEQUAL : ">>=" ;
SHIFTLEFT       : "<<" ;
SHIFTLEFTEQUAL  : "<<=" ;

AND            : "&&" ;
NOT            : '!' ;
OR             : "||" ;

AMPERSAND       : '&' ;
BITWISEANDEQUAL : "&=" ;
TILDE           : '~' ;
BITWISEOR       : '|' ;
BITWISEOREQUAL  : "|=" ;
BITWISEXOR      : '^' ;
BITWISEXOREQUAL : "^=" ;

//Zuo: the following tokens are come from cplusplus.g

POINTERTOMBR    : "->*" ;
DOTMBR          : ".*"  ;

SCOPE           : "::"  ;

// DW 10/10/02
// Whitespace -- ignored
Whitespace
  : ( (' ' |'\t' | '\f')
      // handle newlines
    | ( "\r\n"  // MS
      | '\r'    // Mac
      | '\n'    // Unix
      ) { newline(); }
      // handle continuation lines
    | ( "\\\r\n"  // MS
      | "\\\r"    // Mac
      | "\\\n"    // Unix
      )
    )
    {$setType(Token.SKIP); }
  ;

Comment
  : "/*"
    ( {LA(2) != '/'}? '*'
    | EndOfLine {newline();}
    | ~('*'| '\r' | '\n')
    )*
    "*/"
    {$setType(Token.SKIP);}
  ;

CPPComment
  : "//" (~('\n' | '\r'))* EndOfLine
    {$setType(Token.SKIP);newline();}
  ;

DIRECTIVE
  : '#' ld:LineDirective
    { $setType(Token.SKIP);  newline();}
  ;

protected
LineDirective
  :
    (~('\r'|'\n'))* EndOfLine
  ;

/* Literals: */

/*
 * Note that we do NOT handle tri-graphs nor multi-byte sequences.
 */

/*
 * Note that we can't have empty character constants (even though we
 * can have empty strings :-).
 */
CharLiteral
  : '\'' (Escape | ~( '\'' )) '\''
  ;

/*
 * Can't have raw imbedded newlines in string constants.  Strict reading of
 * the standard gives odd dichotomy between newlines & carriage returns.
 * Go figure.
 */
StringLiteral
  : '"'
    ( Escape
    | ( "\\\r\n"   // MS
      | "\\\r"     // MAC
      | "\\\n"     // Unix
      ) {newline();}
    | ~('"' | '\r' | '\n' | '\\')
    )*
    '"'
  ;

protected
EndOfLine
  : ( options{generateAmbigWarnings = false;}:
      "\r\n"  // MS
    | '\r'    // Mac
    | '\n'    // Unix
    )
  ;

/*
 * Handle the various escape sequences.
 *
 * Note carefully that these numeric escape *sequences* are *not* of the
 * same form as the C language numeric *constants*.
 *
 * There is no such thing as a binary numeric escape sequence.
 *
 * Octal escape sequences are either 1, 2, or 3 octal digits exactly.
 *
 * There is no such thing as a decimal escape sequence.
 *
 * Hexadecimal escape sequences are begun with a leading \x and continue
 * until a non-hexadecimal character is found.
 *
 * No real handling of tri-graph sequences, yet.
 */

protected
Escape
  : '\\'
    ( options{warnWhenFollowAmbig=false;}:
      'a'
    | 'b'
    | 'f'
    | 'n'
    | 'r'
    | 't'
    | 'v'
    | '"'
    | '\''
    | '\\'
    | '?'
    | ('0'..'3') (options{warnWhenFollowAmbig=false;}: Digit (options{warnWhenFollowAmbig=false;}: Digit)? )?
    | ('4'..'7') (options{warnWhenFollowAmbig=false;}: Digit)?
    | 'x' (options{warnWhenFollowAmbig=false;}: Digit | 'a'..'f' | 'A'..'F')+
    )
  ;

/* Numeric Constants: */

protected
Digit
  : '0'..'9'
  ;

protected
Decimal
  : ('0'..'9')+
  ;

protected
LongSuffix
  : 'l'
  | 'L'
  ;

protected
UnsignedSuffix
  : 'u'
  | 'U'
  ;

protected
FloatSuffix
  : 'f'
  | 'F'
  ;

protected
Exponent
  : ('e' | 'E') ('+' | '-')? (Digit)+
  ;

protected
Vocabulary
  : '\3'..'\377'
  ;

Number
  : ( (Digit)+ ('.' | 'e' | 'E') )=> (Digit)+
    ( '.' (Digit)* (Exponent)? {$setType ( FLOATONE);} //Zuo 3/12/01
    | Exponent                 {$setType (FLOATTWO);} //Zuo 3/12/01
    )
    (FloatSuffix
    |LongSuffix
    )?

  | ("...")=> "..."            {$setType (ELLIPSIS);}

  | '.'                        {$setType (DOT);}
    ( (Digit)+ (Exponent)?   {$setType (FLOATONE);} //Zuo 3/12/01
                                   //{_ttype = DoubleDoubleConst;}
      (FloatSuffix           //{_ttype = FloatDoubleConst;}
      |LongSuffix            //{_ttype = LongDoubleConst;}
      )?
    )?

  | '0' ('0'..'7')*            //{_ttype = IntOctalConst;}
    (LongSuffix                //{_ttype = LongOctalConst;}
    |UnsignedSuffix            //{_ttype = UnsignedOctalConst;}
    )*                         {$setType( OCTALINT);}

  | '1'..'9' (Digit)*          //{_ttype = IntIntConst;}
    (LongSuffix                //{_ttype = LongIntConst;}
    |UnsignedSuffix            //{_ttype = UnsignedIntConst;}
    )*                         {$setType( DECIMALINT);}

  | '0' ('x' | 'X') ('a'..'f' | 'A'..'F' | Digit)+
                                   //{_ttype = IntHexConst;}
    (LongSuffix                //{_ttype = LongHexConst;}
    |UnsignedSuffix            //{_ttype = UnsignedHexConst;}
    )*                         {$setType( HEXADECIMALINT);}
  ;

ID
  options {testLiterals = true;}
  : ( 'a'..'z' | 'A'..'Z' | '_' )
    ( 'a'..'z' | 'A'..'Z' | '_' | '0'..'9' )*
  ;
